home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / CNews / Source / explode / trbatch.c < prev   
Encoding:
C/C++ Source or Header  |  1992-04-18  |  4.9 KB  |  219 lines

  1. /*
  2.  * transmit batch file management (exploder version)
  3.  */
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include "hdbm.h"
  7. #include "hash.h"
  8. #include "libc.h"
  9. #include "news.h"
  10. /* tunable parameter */
  11. #ifndef NOPENBFS
  12. #define NOPENBFS 250    /* # batchfiles kept open for batching */
  13. #endif            /* NOPENBFS */
  14. #include "trbatch.h"
  15.  
  16. /* tunable parameters */
  17. #ifndef HASHFILSZ
  18. #define HASHFILSZ (NOPENBFS/2)
  19.             /* # of hash buckets for batch file names */
  20. #endif            /* HASHFILSZ */
  21.  
  22. static HASHTABLE *nmbftbl;        /* name -> batchfile mapping */
  23.  
  24. /*
  25.  * open "name" for appending.
  26.  *
  27.  * see if any batchfile has been assigned to "name" yet.
  28.  * if an attempt to open the batchfile's stream fails, close an arbitrary
  29.  * batchfile stream and retry the open.
  30.  */
  31. struct batchfile *
  32. bfopen(name)
  33. register char *name;
  34. {
  35.     register struct batchfile *bf;
  36.  
  37.     /* malloc_debug(0); */                /* DEBUG */
  38.     bf = bfincache(name);
  39.     if (bf->bf_str == NULL) {
  40.         bf->bf_str = fopenclex(name, "a");    /* silent try */
  41.         if (bf->bf_str == NULL) {
  42.             if (bfrclose() != ST_OKAY)
  43.                 return NULL;
  44.             errno = 0;
  45.             warning(
  46.     "had to close a descriptor to reuse it; this should not happen!\n",
  47.                  "");
  48.             /* retry, may bitch */
  49.             bf->bf_str = fopenwclex(name, "a");
  50.         }
  51.         if (bf->bf_str != NULL)
  52.             bfsetup(bf);
  53.     }
  54.     if (bf->bf_str == NULL)
  55.         error("can't open %s", name);
  56.     return bf;
  57. }
  58.  
  59. /*
  60.  * returns a batchfile, never NULL, corresponding to name.
  61.  */
  62. struct batchfile *
  63. bfincache(name)
  64. char *name;
  65. {
  66.     register struct batchfile *bf;
  67.  
  68.     bf = bfisopen(name);
  69.     if (bf == NULL) {
  70.         hfinstall(name);
  71.         bf = bfisopen(name);
  72.         if (bf == NULL)
  73.             abort();    /* DEBUG */
  74.     }
  75.     return bf;
  76. }
  77.  
  78. /*
  79.  * write filename, message-id or size on batch file "bf".
  80.  * under the 'f' flag, include the size in bytes of the article
  81.  * after "name" to assist the C news batcher.  under the 'n' flag,
  82.  * write the article's message-id.  afterward, flush "bf" in case
  83.  * the machine crashes before the stream is closed.
  84.  * don't check putc return value for portability; use ferror.
  85.  */
  86. int                            /* boolean */
  87. bfappend(bf, flag, batname, artname, msgid, size)
  88. register struct batchfile *bf;
  89. int flag;
  90. char *batname, *artname, *msgid;
  91. long size;
  92. {
  93.     register FILE *bfstr = bf->bf_str;
  94.  
  95.     if (flag == 'I')
  96.         artname = msgid;            /* cheat */
  97.     if (fputs(artname, bfstr) == EOF)
  98.         return NO;
  99.     if (flag == 'f' && fprintf(bfstr, " %ld", size) == EOF)
  100.         return NO;
  101.     if (flag == 'n') {
  102.         (void) putc(' ', bfstr);
  103.         if (ferror(bfstr) || fputs(msgid, bfstr) == EOF)
  104.             return NO;
  105.     }
  106.     (void) putc('\n', bfstr);
  107.     if (ferror(bfstr) || bfflush(bf) == EOF)
  108.         return NO;
  109.     return YES;        
  110. }
  111.  
  112. /* --- hashing --- */
  113.  
  114. struct closehook {
  115.     short    closedone;
  116.     statust    status;
  117. };
  118.  
  119. STATIC int
  120. closefirst(key, data, hook)
  121. HASHDATUM key, data;
  122. char *hook;
  123. {
  124.     register struct closehook *chp = (struct closehook *)hook;
  125.     register struct batchfile *bf;
  126.  
  127.     if (chp->closedone)
  128.         return;
  129.     bf = (struct batchfile *)data;
  130.     if (bf->bf_str == NULL)
  131.         return;
  132.     chp->status = bfclose(bf);
  133.     chp->closedone = YES;
  134. }
  135.  
  136. STATIC statust
  137. bfrclose()                /* close an arbitrary batchfile */
  138. {
  139.     struct closehook closehook;
  140.     register struct closehook *chp = &closehook;
  141.  
  142.     chp->closedone = NO;
  143.     chp->status = ST_OKAY;
  144.     if (nmbftbl == NULL)
  145.         return chp->status;
  146.     hashwalk(nmbftbl, closefirst, (char *)chp);
  147.     if (!chp->closedone) {
  148.         errno = 0;
  149.         warning("bfrclose couldn't find an open descriptor to close",
  150.             "");
  151.     }
  152.     return chp->status;
  153. }
  154.  
  155. STATIC int
  156. closeone(key, data, hook)        /* close a given open batch file */
  157. HASHDATUM key, data;
  158. char *hook;
  159. {
  160.     register struct closehook *chp = (struct closehook *)hook;
  161.     register struct batchfile *bf = (struct batchfile *)data;
  162.  
  163.     if (bf->bf_str != NULL)        /* batch file stream open */
  164.         chp->status |= bfclose(bf);
  165. #ifdef notdef
  166.     bf->bf_ref = 0;
  167. #endif
  168.     if (!hashdelete(nmbftbl, key))
  169.         error("can't delete hash key `%s'", key);
  170. }
  171.  
  172. STATIC statust
  173. bfrealclose()                /* close all open batch files */
  174. {
  175.     struct closehook closehook;
  176.     register struct closehook *chp = &closehook;
  177.  
  178.     chp->status = ST_OKAY;
  179.     if (nmbftbl != NULL)
  180.         hashwalk(nmbftbl, closeone, (char *)chp);
  181.     return chp->status;
  182. }
  183.  
  184. STATIC
  185. hfinstall(name)
  186. char *name;
  187. {
  188.     register struct batchfile *bf;
  189.  
  190.     if (nmbftbl == NULL)
  191.         nmbftbl = hashcreate(HASHFILSZ, (unsigned (*)())NULL);
  192.     bf = (struct batchfile *)hashfetch(nmbftbl, name);
  193.     if (bf != NULL)
  194.         return;            /* error: name present */
  195.     /* allocate, append & initialise a new entry */
  196.     bf = (struct batchfile *)nemalloc(sizeof *bf);
  197.     (void) memset((char *)bf, 0, sizeof *bf);
  198.     bf->bf_name = strsave(name);    /* NEEDED? */
  199.     bf->bf_str = NULL;    /* paranoia */
  200. #ifdef notdef
  201.     bf->bf_ref = 0;
  202. #endif
  203.     bf->bf_lines = FLUSHEVERY;
  204.     if (!hashstore(nmbftbl, bf->bf_name, (HASHDATUM)bf))
  205.         error("can't store under hash key `%s'", name);
  206. }
  207.  
  208. /*
  209.  * search the batchfile cache for "name"; return the corresponding
  210.  * open master batch file, if any.
  211.  */
  212. STATIC struct batchfile *
  213. bfisopen(name)
  214. char *name;
  215. {
  216.     return nmbftbl == NULL? NULL:
  217.         (struct batchfile *)hashfetch(nmbftbl, name);
  218. }
  219.